package com.sc.nft.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.sc.nft.dao.*;
import com.sc.nft.entity.*;
import com.sc.nft.entity.dto.AddActivityPropsConfDTO;
import com.sc.nft.entity.vo.*;
import com.sc.nft.enums.*;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.pool.UserPool;
import com.sc.nft.service.ActivityPropsService;
import com.sc.nft.service.EcologyPoolService;
import com.sc.nft.service.MallUserActivitySummaryService;
import com.sc.nft.service.UserAssetsService;
import com.sc.nft.service.UserEquityPropsService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;


@Slf4j
@RequiredArgsConstructor
@Service
public class ActivityPropsServiceImpl implements ActivityPropsService {
    private final EquityPropsDao equityPropsDao;
    private final ActivityPropsConfDao activityPropsConfDao;
    private final ActivityPropsDao activityPropsDao;
    private final DigitalCollectionDao digitalCollectionDao;
    private final UserEquityPropsDao userEquityPropsDao;
    private final UserAssetsDao userAssetsDao;
    private final UserEquityPropsService userEquityPropsService;
    private final UserAssetsService userAssetsService;
    private final UserCollectionDao userCollectionDao;
    private final EcologyPoolService ecologyPoolService;
    private final EcologyPoolDao ecologyPoolDao;
    private final UserCreatorInfoDao userCreatorInfoDao;
    private final MallUserActivitySummaryService mallUserActivitySummaryService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addActivityProps(Long equityPropsId, Integer sumCount, String creationContent, Long relationId, String relationName, List<AddActivityPropsConfDTO> confList, Integer upperLimit, Boolean isRegisterTime, Date registerBeginTime, Date registerEndTime, BoxTakePoolConvertScenarioEnum convertScenario, Long daoId) {
        ActivityProps activityProps = new ActivityProps();
        EquityProps equityProps = equityPropsDao.getById(equityPropsId);
        if (ObjectUtil.isNull(equityProps)) {
            throw new GlobalRunTimeException("不存在此道具卡");
        }
        if (sumCount < upperLimit) {
            throw new GlobalRunTimeException("兑换上限不能大于总数量");
        }
        if (Objects.equals(convertScenario, BoxTakePoolConvertScenarioEnum.DAO_CONVERT)) {
            if (Objects.isNull(daoId)) {
                throw new GlobalRunTimeException("DAO内兑换品牌ID不能为空");
            }
        }
        //新增道具卡
        activityProps.setConvertScenario(convertScenario);
        activityProps.setDaoId(Objects.equals(convertScenario, BoxTakePoolConvertScenarioEnum.DAO_CONVERT) ? daoId : null);
        activityProps.setEquityPropsId(equityPropsId);
        activityProps.setStatus(Boolean.FALSE);
        activityProps.setSort(0);
        activityProps.setFirstTitle(equityProps.getFirstTitle());
        activityProps.setSumCount(sumCount);
        activityProps.setUsableCount(sumCount);
        activityProps.setExchangeCount(0);
        activityProps.setCreationContent(creationContent);
        activityProps.setUpperLimit(upperLimit);
        activityProps.setIsRegisterTime(isRegisterTime);
        if (isRegisterTime) {
            if (ObjectUtil.isNull(registerBeginTime) || ObjectUtil.isNull(registerEndTime)) {
                throw new GlobalRunTimeException("注册时间不能为空");
            }
            if (registerBeginTime.after(registerEndTime)) {
                throw new GlobalRunTimeException("注册开始时间不能大于结束时间");
            }
            activityProps.setRegisterBeginTime(registerBeginTime);
            activityProps.setRegisterEndTime(registerEndTime);
        }


        activityProps.insert();
        //新增道具卡配置
        ArrayList<ActivityPropsConf> addList = Lists.newArrayList();
        //参与对象条件
        if (ObjectUtil.isNotNull(relationId)) {
            DigitalCollection collection = digitalCollectionDao.getById(relationId);
            if (ObjectUtil.isNull(collection)) {
                throw new GlobalRunTimeException("找不到参与对象对应的藏品");
            }
            ActivityPropsConf joinObject = new ActivityPropsConf();
            joinObject.setType(ActivityPropsConfTypeEnum.OBJECT_OF_PARTICIPATION);
            joinObject.setRelationType(PropsRelationTypeEnum.COLLECTION);
            joinObject.setCostCount(BigDecimal.ZERO);
            joinObject.setRelationId(relationId);
            joinObject.setRelationName(collection.getFirstTitle());
            joinObject.setActivityPropsId(activityProps.getId());
            addList.add(joinObject);
        }
        //兑换条件
        confList.forEach(c -> {
            ActivityPropsConf activityPropsConf = new ActivityPropsConf();
            if (c.getRelationType() == PropsRelationTypeEnum.EQUITY_PROPS) {
                EquityProps props = equityPropsDao.getById(c.getRelationId());
                if (ObjectUtil.isNull(props)) {
                    throw new GlobalRunTimeException(StrUtil.format("不存在id为{}的道具", c.getRelationId()));
                }
                activityPropsConf.setRelationName(props.getFirstTitle());
            }
            if (c.getRelationType() == PropsRelationTypeEnum.STAR_FRAGMENT) {
                activityPropsConf.setRelationName("星球碎片");
            }
            if (c.getRelationType() == PropsRelationTypeEnum.ECOLOGY_POOL_POINTS) {
                activityPropsConf.setRelationName("生态积分");
            }
            if (c.getRelationType() == PropsRelationTypeEnum.EXCHANGE_LIMIT) {
                activityPropsConf.setRelationName(PropsRelationTypeEnum.EXCHANGE_LIMIT.getName());
            }
            activityPropsConf.setActivityPropsId(activityProps.getId());
            activityPropsConf.setType(ActivityPropsConfTypeEnum.EXCHANGE);
            activityPropsConf.setCostCount(c.getCostCount());
            activityPropsConf.setRelationId(c.getRelationId());
            activityPropsConf.setRelationType(c.getRelationType());
            addList.add(activityPropsConf);
        });
        activityPropsConfDao.saveBatch(addList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateActivityProps(Long id, Long relationId, String relationName, List<AddActivityPropsConfDTO> confList, Integer upperLimit, Boolean isRegisterTime, Date registerBeginTime, Date registerEndTime, Long daoId) {
        ActivityProps activityProps = activityPropsDao.getById(id);
        if (ObjectUtil.isNull(activityProps)) {
            throw new GlobalRunTimeException("不存在此活动道具卡");
        }
        if (activityProps.getStatus()) {
            throw new GlobalRunTimeException("上架中不能修改");
        }
        //更新兑换上限
        Boolean requireUpdate = false;
        if (upperLimit != activityProps.getUpperLimit()) {
            activityProps.setUpperLimit(upperLimit);
            requireUpdate = true;
        }
        //更新品牌
        if (Objects.equals(activityProps.getConvertScenario(), BoxTakePoolConvertScenarioEnum.DAO_CONVERT)) {
            if (Objects.isNull(daoId)) {
                throw new GlobalRunTimeException("品牌不能为空");
            }
            if (!Objects.equals(daoId, activityProps.getDaoId())) {
                activityProps.setDaoId(daoId);
                requireUpdate = true;
            }
        }
        if (requireUpdate) {
            activityProps.updateById();
        }
        if (isRegisterTime) {
            if (ObjectUtil.isNull(registerBeginTime) || ObjectUtil.isNull(registerEndTime)) {
                throw new GlobalRunTimeException("注册时间不能为空");
            }
            if (registerBeginTime.after(registerEndTime)) {
                throw new GlobalRunTimeException("注册开始时间不能大于结束时间");
            }

        }

        //修改时间
        activityPropsDao.updateRegisterTimeById(activityProps, isRegisterTime, registerBeginTime, registerEndTime);

        //更新道具卡配置(删除再新增)
        activityPropsConfDao.deleteByActivityPropsId(id);
        ArrayList<ActivityPropsConf> addList = Lists.newArrayList();
        //参与对象条件
        if (ObjectUtil.isNotNull(relationId)) {
            DigitalCollection collection = digitalCollectionDao.getById(relationId);
            if (ObjectUtil.isNull(collection)) {
                throw new GlobalRunTimeException("找不到参与对象对应的藏品");
            }
            ActivityPropsConf joinObject = new ActivityPropsConf();
            joinObject.setType(ActivityPropsConfTypeEnum.OBJECT_OF_PARTICIPATION);
            joinObject.setRelationType(PropsRelationTypeEnum.COLLECTION);
            joinObject.setCostCount(BigDecimal.ZERO);
            joinObject.setRelationId(relationId);
            joinObject.setRelationName(collection.getFirstTitle());
            joinObject.setActivityPropsId(activityProps.getId());
            addList.add(joinObject);
        }
        //兑换条件
        confList.forEach(c -> {
            ActivityPropsConf activityPropsConf = new ActivityPropsConf();
            if (c.getRelationType() == PropsRelationTypeEnum.EQUITY_PROPS) {
                EquityProps props = equityPropsDao.getById(c.getRelationId());
                if (ObjectUtil.isNull(props)) {
                    throw new GlobalRunTimeException(StrUtil.format("不存在id为{}的道具", c.getRelationId()));
                }
                activityPropsConf.setRelationName(props.getFirstTitle());
            }
            if (c.getRelationType() == PropsRelationTypeEnum.STAR_FRAGMENT) {
                activityPropsConf.setRelationName("星球碎片");
            }
            if (c.getRelationType() == PropsRelationTypeEnum.ECOLOGY_POOL_POINTS) {
                activityPropsConf.setRelationName("生态积分");
            }
            activityPropsConf.setActivityPropsId(activityProps.getId());
            activityPropsConf.setType(ActivityPropsConfTypeEnum.EXCHANGE);
            activityPropsConf.setCostCount(c.getCostCount());
            activityPropsConf.setRelationId(c.getRelationId());
            activityPropsConf.setRelationType(c.getRelationType());
            addList.add(activityPropsConf);
        });
        activityPropsConfDao.saveBatch(addList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteActivityProps(Long id) {
        ActivityProps activityProps = activityPropsDao.getById(id);
        if (ObjectUtil.isNull(activityProps)) {
            throw new GlobalRunTimeException("不存在此活动道具卡");
        }
        if (activityProps.getStatus()) {
            throw new GlobalRunTimeException("该道具卡正在上架中");
        }
        //删除道具卡数据
        activityPropsDao.removeById(id);
        //删除道具卡配置数据
        activityPropsConfDao.deleteByActivityPropsId(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateStatus(Long id, Boolean status) {
        Assert.isTrue(activityPropsDao.updateStatus(id, status), () -> new GlobalRunTimeException("上下架失败"));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateSort(Long id, Integer sort) {
        Assert.isTrue(activityPropsDao.updateSort(id, sort), () -> new GlobalRunTimeException("修改排序失败"));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUsableCount(Long id, Integer count) {
        ActivityProps activityProps = activityPropsDao.getById(id);
        if (activityProps.getStatus()) {
            throw new GlobalRunTimeException("上架中不允许修改");
        }
        //取新值和旧值的差值 为调整数量
        Integer difCount = count - activityProps.getUsableCount();
        Integer sumCount = activityProps.getSumCount() + difCount;
        //更新可用数量
        Assert.isTrue(activityPropsDao.updateUsableCount(id, count), () -> new GlobalRunTimeException("修改数量失败"));
        //更新总数量
        Assert.isTrue(activityPropsDao.updateSumCount(id, sumCount), () -> new GlobalRunTimeException("修改数量失败"));
    }

    @Override
    public Page<ActivityPropsVO> adminPage(Boolean status, String firstTitle, BoxTakePoolConvertScenarioEnum convertScenario, Long daoId, Integer pageNo, Integer pageSize) {
        Page<ActivityPropsVO> result = activityPropsDao.adminPage(status, firstTitle, convertScenario, daoId, pageNo, pageSize);
        if (result.getRecords().size() == 0) {
            return result;
        }

        List<Long> activityPropsIdList = result.getRecords().stream().map(ActivityPropsVO::getId).collect(Collectors.toList());
        List<ActivityPropsConf> activityPropsConfList = activityPropsConfDao.getByPropsIdList(activityPropsIdList);
        if (activityPropsIdList.size() == 0) {
            return result;
        }
        Map<Long, List<ActivityPropsConf>> map = activityPropsConfList.stream().filter(a -> a.getType() == ActivityPropsConfTypeEnum.EXCHANGE).collect(Collectors.groupingBy(ActivityPropsConf::getActivityPropsId));
        result.getRecords().forEach(r -> {
            //取这个活动道具卡的参与活动条件
            List<ActivityPropsConf> joinList = activityPropsConfList.stream().filter(a -> a.getType() == ActivityPropsConfTypeEnum.OBJECT_OF_PARTICIPATION && a.getActivityPropsId().equals(r.getId())).collect(Collectors.toList());
            if (CollUtil.isEmpty(joinList)) {
                r.setJoin("无");
            } else {
                r.setJoin(joinList.get(0).getRelationName());
            }
            //取兑换条件拼接
            List<ActivityPropsConf> exchangeList = map.get(r.getId());
            String needProps = exchangeList.stream().map(e -> e.getRelationName() + '*' + e.getCostCount().toString()).collect(Collectors.joining(","));
            r.setNeedProps(needProps);
            //品牌名称
            if (Objects.nonNull(r.getDaoId())) {
                GetDaoByIdVO getDaoByIdVO = userCreatorInfoDao.getDaoById(r.getDaoId());
                if (Objects.nonNull(getDaoByIdVO)) {
                    r.setDaoName(getDaoByIdVO.getDaoName());
                }
            }
        });
        return result;
    }

    @Override
    public ActivityPropsDetailVO getActivityPropsById(Long id) {
        ActivityProps activityProps = activityPropsDao.getById(id);
        ActivityPropsDetailVO result = BeanUtil.copyProperties(activityProps, ActivityPropsDetailVO.class);
        List<ActivityPropsConf> exChangePropsList = activityPropsConfDao.getExchangeByPropsId(id);
        ActivityPropsConf joinObject = activityPropsConfDao.getJoinObjectByPropsId(id);
        if (ObjectUtil.isNull(joinObject)) {
            result.setIsJoin(Boolean.FALSE);
            result.setRelationName(StrUtil.EMPTY);
        } else {
            result.setRelationId(joinObject.getRelationId());
            result.setRelationName(joinObject.getRelationName());
            result.setIsJoin(Boolean.TRUE);
        }
        List<ActivityPropsConfVO> confList = Lists.newArrayList();
        exChangePropsList.forEach(e -> confList.add(BeanUtil.copyProperties(e, ActivityPropsConfVO.class)));
        result.setConfList(confList);
        if (Objects.nonNull(result.getDaoId())) {
            GetDaoByIdVO getDaoByIdVO = userCreatorInfoDao.getDaoById(result.getDaoId());
            if (Objects.nonNull(getDaoByIdVO)) {
                result.setDaoName(getDaoByIdVO.getDaoName());
            }
        }
        return result;
    }

    @Override
    public Page<ActivityPropsUpVO> getUpActivityPropsList(BoxTakePoolConvertScenarioEnum convertScenario, Long daoId, Integer pageNo, Integer pageSize) {
        return activityPropsDao.getUpActivityPropsList(convertScenario, daoId, pageNo, pageSize);
    }

    @Override
    public ActivityPropsExchangeDetailVO getActivityPropsDetail(Long id) {
        UserInfo user = UserPool.getUser();
        ActivityProps activityProps = activityPropsDao.getById(id);
        ActivityPropsExchangeDetailVO result = BeanUtil.copyProperties(activityProps, ActivityPropsExchangeDetailVO.class);
        if (result.getIsRegisterTime()) {
            if (user.getCreateTime().after(result.getRegisterBeginTime()) && user.getCreateTime().before(result.getRegisterEndTime()) ||
                    user.getCreateTime().equals(result.getRegisterBeginTime()) || user.getCreateTime().equals(result.getRegisterEndTime())
            ) {
                result.setIsConforRegisterTime(Boolean.TRUE);
            }
        }

        EquityProps equityProps = equityPropsDao.getById(activityProps.getEquityPropsId());
        //不过期的道具卡设置的过期天数是3650
        if (equityProps.getExpiredDay() == 3650) {
            result.setIsExpired(Boolean.TRUE);
        } else {
            result.setIsExpired(Boolean.FALSE);
        }
        result.setExpiredDay(equityProps.getExpiredDay());
        result.setUpperLimit(activityProps.getUpperLimit());
        //查询已获取数量填充属性  后续填充可兑换数量的前置
        UserEquityPropsVO equityCountVo = userEquityPropsDao.getMyEquityCount(id, user.getId(), activityProps.getEquityPropsId());
        result.setRedeemedQuantity(Objects.isNull(equityCountVo) ? 0 : equityCountVo.getHasCount());
        //参与对象
        ActivityPropsConf joinObject = activityPropsConfDao.getJoinObjectByPropsId(id);
        if (ObjectUtil.isNull(joinObject)) {
            result.setIsJoin(Boolean.FALSE);
            result.setIsHoldJoin(Boolean.FALSE);
//          result.setJoinName(StrUtil.EMPTY);
//          result.setJoinImage(StrUtil.EMPTY);
        } else {
            result.setIsJoin(Boolean.TRUE);
            result.setJoinName(joinObject.getRelationName());
            //持有的NFT缩略图
            DigitalCollection collection = digitalCollectionDao.getById(joinObject.getRelationId());
            if (ObjectUtil.isNotNull(collection)) {
                result.setJoinImage(collection.getCreationContent());
            }
            //是否持有该NFT
            Integer count = userCollectionDao.getHoldOpenCountByCollectionId(joinObject.getRelationId(), user.getId());
            if (count > 0) {
                result.setIsHoldJoin(Boolean.TRUE);
            } else {
                result.setIsHoldJoin(Boolean.FALSE);
            }
        }
        //兑换消耗
        List<ActivityPropsConf> exchangePropsList = activityPropsConfDao.getExchangeByPropsId(id);
        List<ActivityPropsConfExchangeVO> confList = Lists.newArrayList();
        exchangePropsList.forEach(e -> {
            ActivityPropsConfExchangeVO exchangeVO = BeanUtil.copyProperties(e, ActivityPropsConfExchangeVO.class);
            //查询每个消耗种类拥有的存量
            if (e.getRelationType() == PropsRelationTypeEnum.STAR_FRAGMENT) {
                UserAssets userAssets = userAssetsDao.getByUserIdAndCoinId(user.getId(), CoinCategoryEnum.INTEGRAL.getCode());
                if (ObjectUtil.isNotEmpty(userAssets)) {
                    exchangeVO.setHasCount(userAssets.getTokenNum().setScale(2, BigDecimal.ROUND_DOWN).toString());
                }

            }
            if (e.getRelationType() == PropsRelationTypeEnum.EQUITY_PROPS) {
                Integer count = userEquityPropsDao.getHavingCountByUserId(e.getRelationId(), user.getId());
                exchangeVO.setHasCount(count.toString());
            }
            //生态积分
            if (e.getRelationType() == PropsRelationTypeEnum.ECOLOGY_POOL_POINTS) {
                EcologyPool ecologyPool = (Objects.equals(activityProps.getConvertScenario(), BoxTakePoolConvertScenarioEnum.DAO_CONVERT) && Objects.nonNull(activityProps.getDaoId())) ? ecologyPoolDao.getByTypeAndDaoIdUserId(EcologyPoolTypeEnum.ACCOUNT, EcologyPoolLinkTypeEnum.POINTS, activityProps.getDaoId(), user.getId()) : null;
                exchangeVO.setHasCount(Objects.nonNull(ecologyPool) ? ecologyPool.getLinkCount().toPlainString() : "0.00");
            }
            //兑换额度
            if (e.getRelationType() == PropsRelationTypeEnum.EXCHANGE_LIMIT) {
                MallUserActivitySummary mallUserActivitySummary = mallUserActivitySummaryService.get(user.getId());
                exchangeVO.setHasCount(mallUserActivitySummary == null ? "0" : String.valueOf(mallUserActivitySummary.getTotalConsumptionAmount().subtract(mallUserActivitySummary.getTotalExchangeAmount()).intValue()));
            }

            confList.add(exchangeVO);
        });
        result.setConfList(confList);
        //设定可兑换数量
        result.setSurplusCount();
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void exchange(Long id, Integer num) {
        UserInfo user = UserPool.getUser();
        ActivityProps activityProps = activityPropsDao.getById(id);
        EquityProps equityProps = equityPropsDao.getById(activityProps.getEquityPropsId());
        if (!activityProps.getStatus()) {
            throw new GlobalRunTimeException("该活动道具卡已下架");
        }
        if (!user.getIsSm()) {
            throw new GlobalRunTimeException("请先进行实名认证");
        }

        if (activityProps.getIsRegisterTime()) {
            Assert.isTrue(user.getCreateTime().after(activityProps.getRegisterBeginTime()), () -> new GlobalRunTimeException("注册时间不符合"));
            Assert.isTrue(user.getCreateTime().before(activityProps.getRegisterEndTime()), () -> new GlobalRunTimeException("注册时间不符合"));
        }

        ActivityPropsConf joinObjectConf = activityPropsConfDao.getJoinObjectByPropsId(id);
        if (ObjectUtil.isNotEmpty(joinObjectConf)) {
            Integer count = userCollectionDao.getCountByCollectionIdAndUserId(joinObjectConf.getRelationId(), user.getId());
            if (count == 0) {
                throw new GlobalRunTimeException("未满足持有NFT兑换条件");
            }
        }
        //判断用户已购买数量是否已达上限
        UserEquityPropsVO equityCount = userEquityPropsDao.getMyEquityCount(id, user.getId(), activityProps.getEquityPropsId());
        if (!Objects.isNull(equityCount) && !Objects.isNull(activityProps.getUpperLimit()) && equityCount.getHasCount() >= activityProps.getUpperLimit()) {
            throw new GlobalRunTimeException("兑换已达上限");
        }

        if (activityProps.getUsableCount() < num) {
            throw new GlobalRunTimeException("可用库存不足");
        }
        List<ActivityPropsConf> exchangeProps = activityPropsConfDao.getExchangeByPropsId(id);
        //判断每个条件是否都满足
        exchangeProps.forEach(e -> {
            if (e.getRelationType() == PropsRelationTypeEnum.STAR_FRAGMENT) {
                UserAssets userAssets = userAssetsDao.getByUserIdAndCoinId(user.getId(), CoinCategoryEnum.INTEGRAL.getCode());
                if (ObjectUtil.isNull(userAssets)) {
                    throw new GlobalRunTimeException("未找到对应的星球碎片账户");
                }
                //星球碎片保留两位来比较
                BigDecimal totalNum = NumberUtil.mul(e.getCostCount(), BigDecimal.valueOf(num)).setScale(2, BigDecimal.ROUND_DOWN);
                if (NumberUtil.isGreater(totalNum, userAssets.getTokenNum().setScale(2, BigDecimal.ROUND_DOWN))) {
                    throw new GlobalRunTimeException("星球碎片余额不足");
                }
                //扣除星球碎片
                Assert.isTrue(userAssetsService.subIntegralByUserId(totalNum, user.getId(), CoinCategoryEnum.INTEGRAL, AssetChangeLogEnum.PROPS_EXCHANGE, id, "兑换：" + activityProps.getFirstTitle() + "x" + num), () -> new GlobalRunTimeException("兑换失败"));

            }
            if (e.getRelationType() == PropsRelationTypeEnum.EQUITY_PROPS) {
                Integer count = userEquityPropsDao.getHavingCountByUserId(e.getRelationId(), user.getId());
                Integer totalCount = e.getCostCount().intValue() * num;
                if (totalCount > count) {
                    throw new GlobalRunTimeException(StrUtil.format("道具{}数量不足", e.getRelationName()));
                }
                List<UserEquityProps> list = userEquityPropsDao.getHavingListByUserIdAndEquityPropsIdAndLimit(e.getRelationId(), user.getId(), totalCount);
                Assert.isTrue(list.size() == totalCount, () -> new GlobalRunTimeException("兑换失败"));
                //扣除权益道具
                Assert.isTrue(userEquityPropsService.normalToconsumeByIds(list, user.getId(), activityProps.getFirstTitle(), activityProps.getId(), UserEquityPropsUseTypeEnum.EXCHANGE), () -> new GlobalRunTimeException("兑换失败"));
            }
            //生态积分
            if (e.getRelationType() == PropsRelationTypeEnum.ECOLOGY_POOL_POINTS) {
                if (Objects.isNull(activityProps.getDaoId())) {
                    throw new GlobalRunTimeException("兑换生态积分品牌ID不能为空");
                }
                //生态积分总和
                BigDecimal totalNum = NumberUtil.mul(e.getCostCount(), BigDecimal.valueOf(num)).setScale(2, BigDecimal.ROUND_DOWN);
                //兑换生态积分
                ecologyPoolService.convertPoints(totalNum, activityProps.getDaoId(), user.getId());
            }
            //兑换额度
            if (e.getRelationType() == PropsRelationTypeEnum.EXCHANGE_LIMIT) {
                Integer totalCount = e.getCostCount().intValue() * num;
                MallUserActivitySummary mallUserActivitySummary = mallUserActivitySummaryService.get(user.getId());
                if(mallUserActivitySummary == null || mallUserActivitySummary.getTotalConsumptionAmount().subtract(mallUserActivitySummary.getTotalExchangeAmount()).intValue() < totalCount){
                    throw new GlobalRunTimeException(StrUtil.format("兑换额度{}数量不足", e.getRelationName()));
                }
                //扣减兑换额度
                mallUserActivitySummaryService.updateTotalExchangeAmount(user.getId(), BigDecimal.valueOf(totalCount));
            }
        });
        //扣减道具卡可用库存
        Assert.isTrue(activityPropsDao.subUsableCount(id, num), () -> new GlobalRunTimeException("兑换失败"));
        //增加道具卡兑换库存
        Assert.isTrue(activityPropsDao.addExchangeCount(id, num), () -> new GlobalRunTimeException("兑换失败"));
        //添加用户道具卡
        Assert.notNull(userEquityPropsService.exchangeEquityPropsByUser(equityProps, user.getId(), UserEquityPropsGetTypeEnum.EXCHANGE, num, activityProps.getFirstTitle(), activityProps.getId(), BigDecimal.ZERO, id, UserEquityPropsGetTypeEnum.EXCHANGE, activityProps.getId()), () -> new GlobalRunTimeException("兑换失败"));
        //添加兑换记录
        ActivityPropsRecord record = new ActivityPropsRecord();
        record.setCount(num);
        record.setFirstTitle(activityProps.getFirstTitle());
        record.setUserId(user.getId());
        record.setActivityPropsId(activityProps.getId());
        record.insert();
        //添加记录详情
        exchangeProps.forEach(e -> {
            ActivityPropsRecordDetail detail = new ActivityPropsRecordDetail();
            detail.setActivityPropsId(activityProps.getId());
            detail.setUserId(user.getId());
            detail.setActivityPropsRecordId(record.getId());
            detail.setCostType(e.getRelationType());
            detail.setCostPropsId(e.getRelationId());
            detail.setCostCount(e.getCostCount().multiply(BigDecimal.valueOf(num)));
            detail.insert();
        });
    }
}